//
// Created by amon.huang on 2021/7/20.
//

#include <cstring>
#include <unistd.h>
#include "MusicConstDefine.h"
#include "jni.h"
#include "FFMpeg.h"

#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

JNICall *pJNICall;
FFMpeg *pFFmpeg;

#define null (NULL)

JavaVM *pJavaVM = nullptr;

static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
    jint fd = -1;
    jclass fdClass = env->FindClass("java/io/FileDescriptor");
    if (fdClass != nullptr) {
        jfieldID fdClassDescriptorFieldID = env->GetFieldID(fdClass, "descriptor", "I");
        if (fdClassDescriptorFieldID != nullptr && fileDescriptor != nullptr) {
            fd = env->GetIntField(fileDescriptor, fdClassDescriptorFieldID);
        }
    }
    LOGE("jni Get FD From File Descriptor %d", fd);
    return fd;
}

extern "C" JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void */*reserved*/) {
    LOGE("JNI_OnLoad -->");
    pJavaVM = vm;
    JNIEnv *env;
    if (pJavaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    return JNI_VERSION_1_4;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nInit(JNIEnv *env, jobject thiz) {
    // TODO: implement nInit()
}

extern "C" JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nPlay(JNIEnv *env, jobject thiz) {
    // TODO: implement nPlay()
    pFFmpeg->play();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nPrepare(JNIEnv *env, jobject thiz, jstring _url,
                                                    jobject listener) {
    const char *url = env->GetStringUTFChars(_url, 0);
    if (pFFmpeg == null) {
        pJNICall = new JNICall(pJavaVM, env, thiz);
        pJNICall->setAudioInfoListener(listener);
        pFFmpeg = new FFMpeg(pJNICall, url);
        pFFmpeg->prepare();
    }
    env->ReleaseStringUTFChars(_url, url);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nPrepareAsync(JNIEnv *env, jobject thiz, jstring url_,
                                                         jobject listener) {
    // TODO: implement nPrepareAsync()
    const char *url = env->GetStringUTFChars(url_, 0);
    if (pFFmpeg == null) {
        pJNICall = new JNICall(pJavaVM, env, thiz);
        pJNICall->setAudioInfoListener(listener);
        pFFmpeg = new FFMpeg(pJNICall, url);
        pFFmpeg->prepareAsync();
    }
    env->ReleaseStringUTFChars(url_, url);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nPrepareFd(JNIEnv *env, jobject thiz,
                                                      jobject file_descriptor, jobject listener) {
    if (pFFmpeg == null) {
        int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
        char path[20];
        sprintf(path, "/proc/self/fd/%d", fd);
        pJNICall = new JNICall(pJavaVM, env, thiz);
        pJNICall->setAudioInfoListener(listener);
        pFFmpeg = new FFMpeg(pJNICall, path);
        pFFmpeg->prepare();
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nPrepareAsyncFd(JNIEnv *env, jobject thiz,
                                                           jobject file_descriptor,
                                                           jobject listener) {
    if (pFFmpeg == null) {
        int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
        char path[20];
        sprintf(path, "/proc/self/fd/%d", fd);
        pJNICall = new JNICall(pJavaVM, env, thiz);
        pJNICall->setAudioInfoListener(listener);
        pFFmpeg = new FFMpeg(pJNICall, path);
        pFFmpeg->prepareAsync();
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nStop(JNIEnv *env, jobject thiz) {
    if (pFFmpeg) {
        pFFmpeg->release();
        delete pFFmpeg;
        pFFmpeg = nullptr;
    }

    if (pJNICall) {
        delete pJNICall;
        pJNICall = nullptr;
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nSeek(JNIEnv *env, jobject thiz, jint second) {
    if (pFFmpeg) {
        pFFmpeg->seek(second);
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_nSetSurface(JNIEnv *env, jobject thiz,
                                                       jobject jSurface) {
    if (pFFmpeg) {
        pFFmpeg->setSurface(jSurface);
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_amon_amonplayer_player_AmonPlayer_setNativeAudioInfoListener(JNIEnv *env, jobject thiz,
                                                                      jobject jListener) {
    if (pJNICall) {
        pJNICall->setAudioInfoListener(jListener);
    }
}